using System;
using System.Collections.Generic;
using NFreeMarker.Ext.Util;
using NFreeMarker.Template;
using NFreeMarker.Template.Utility;

namespace NFreeMarker.Ext.Beans
{
    public class BeansModelCache : ModelCache
    {
        private readonly Dictionary<Type, IModelFactory> _typeToFactory = new Dictionary<Type, IModelFactory>();
        private readonly HashSet<string> _mappedTypeNames = new HashSet<string>();

        private readonly BeansWrapper _wrapper;

        internal BeansModelCache(BeansWrapper wrapper)
        {
            _wrapper = wrapper;
        }
        
        protected override bool IsCacheable(object obj)
        {
            return obj.GetType() != typeof (bool);
        }
        
        protected override ITemplateModel Create(object obj)
        {
            Type type = obj.GetType();

            IModelFactory factory;
            lock (_typeToFactory)
            {
                factory = _typeToFactory.GetValueOrDefault(type);
                if (factory == null)
                {
                    string typeName = type.FullName;
                    // clear mappings when class reloading is detected
                    if (!_mappedTypeNames.Add(typeName))
                    {
                        _typeToFactory.Clear();
                        _mappedTypeNames.Clear();
                        _mappedTypeNames.Add(typeName);
                    }
                    factory = _wrapper.GetModelFactory(type);
                    _typeToFactory.Add(type, factory);
                }
            }
            return factory.Create(obj, _wrapper);
        }
    }
}